package com.weaving.monitor.service;

import com.weaving.monitor.dto.ProdTodayAmountExportDto;
import com.weaving.monitor.entity.ProdProdCardProcess;
import com.weaving.monitor.entity.ProdTodayAmount;
import com.weaving.monitor.entity.SysUser;
import com.weaving.monitor.mapper.FactoryMachineSpeedMapper;
import com.weaving.monitor.mapper.ProdFlawMapper;
import com.weaving.monitor.mapper.ProdProdCardMapper;
import com.weaving.monitor.mapper.ProdProdCardProcessMapper;
import com.weaving.monitor.mapper.ProdTodayAmountMapper;
import com.weaving.monitor.mapper.SysUserMapper;
import com.weaving.monitor.util.FlawTypeUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 生产今日产量导出服务（优化版）
 * 
 * 性能优化策略：
 * 1. 批量查询减少数据库访问次数
 * 2. 缓存重复查询结果
 * 3. 并行处理提高效率
 * 4. 流式处理减少内存占用
 * 
 * @author 系统开发团队
 * @version 2.0
 * @since 2024-01-01
 */
@Service
public class ProdTodayAmountExportOptimizedService {
    
    @Autowired
    private ProdTodayAmountMapper prodTodayAmountMapper;
    
    @Autowired
    private SysUserMapper sysUserMapper;
    
    @Autowired
    private ProdProdCardProcessMapper prodProdCardProcessMapper;
    
    @Autowired
    private ProdProdCardMapper prodProdCardMapper;
    
    @Autowired
    private ProdFlawMapper prodFlawMapper;
    
    @Autowired
    private FactoryMachineSpeedMapper factoryMachineSpeedMapper;
    
    /**
     * 高效导出数据方法
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 导出数据列表
     */
    public List<ProdTodayAmountExportDto> getExportDataOptimized(LocalDate startDate, LocalDate endDate) {
        try {
            System.out.println("开始优化查询生产数据，日期范围：" + startDate + " 到 " + endDate);
            
            // 1. 查询生产数据
            List<ProdTodayAmount> productionData = prodTodayAmountMapper.selectByDateRange(startDate, endDate);
            System.out.println("查询到原始数据条数：" + productionData.size());
            
            if (productionData.isEmpty()) {
                return new ArrayList<>();
            }
            
            // 2. 过滤数据：每个cardId只保留subClothSeq最大的记录
            List<ProdTodayAmount> filteredData = filterMaxSubClothSeq(productionData);
            System.out.println("过滤后数据条数：" + filteredData.size());
            
            // 3. 并行预加载所有关联数据
            CompletableFuture<Map<String, String>> userMapFuture = loadUserDataAsync(filteredData);
            CompletableFuture<Map<String, BigDecimal>> densityMapFuture = loadDensityDataAsync(filteredData);
            CompletableFuture<Map<String, String>> materialMapFuture = loadMaterialDataAsync(filteredData);
            CompletableFuture<Map<String, String>> flawMapFuture = loadFlawDataAsync(filteredData);
            CompletableFuture<Map<String, Integer>> speedMapFuture = loadSpeedDataAsync(filteredData, startDate, endDate);
            
            // 4. 等待所有异步任务完成
            CompletableFuture.allOf(userMapFuture, densityMapFuture, materialMapFuture, flawMapFuture, speedMapFuture).join();
            
            // 5. 获取结果
            Map<String, String> userMap = userMapFuture.get();
            Map<String, BigDecimal> densityMap = densityMapFuture.get();
            Map<String, String> materialMap = materialMapFuture.get();
            Map<String, String> flawMap = flawMapFuture.get();
            Map<String, Integer> speedMap = speedMapFuture.get();
            
            // 6. 构建导出数据
            return buildExportData(filteredData, userMap, densityMap, materialMap, flawMap, speedMap);
            
        } catch (Exception e) {
            System.err.println("优化查询导出数据失败：" + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("优化查询导出数据失败：" + e.getMessage(), e);

        }
    }
    
    /**
     * 过滤数据：每个cardId只保留subClothSeq最大的记录
     */
    private List<ProdTodayAmount> filterMaxSubClothSeq(List<ProdTodayAmount> productionData) {
        Map<String, Integer> maxSubClothSeqMap = productionData.stream()
                .filter(item -> item.getSubClothSeq() != null)
                .collect(Collectors.groupingBy(
                        ProdTodayAmount::getCardId,
                        Collectors.mapping(
                                ProdTodayAmount::getSubClothSeq,
                                Collectors.maxBy(Integer::compareTo)
                        )
                ))
                .entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().orElse(0)
                ));
        
        return productionData.stream()
                .filter(item -> {
                    String cardId = item.getCardId();
                    Integer maxSubClothSeq = maxSubClothSeqMap.get(cardId);
                    if (maxSubClothSeq == null) {
                        return true;
                    }
                    return item.getSubClothSeq() != null && item.getSubClothSeq().equals(maxSubClothSeq);
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 异步加载用户数据
     */
    private CompletableFuture<Map<String, String>> loadUserDataAsync(List<ProdTodayAmount> data) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                Set<String> userIds = data.stream()
                        .map(ProdTodayAmount::getUserId)
                        .collect(Collectors.toSet());
                
                if (userIds.isEmpty()) {
                    return new HashMap<>();
                }
                
                List<SysUser> users = sysUserMapper.selectByIds(new ArrayList<>(userIds));
                return users.stream()
                        .collect(Collectors.toMap(SysUser::getId, SysUser::getUsername));
            } catch (Exception e) {
                System.err.println("异步加载用户数据失败：" + e.getMessage());
                return new HashMap<>();
            }
        });
    }
    
    /**
     * 异步加载密度数据
     */
    private CompletableFuture<Map<String, BigDecimal>> loadDensityDataAsync(List<ProdTodayAmount> data) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                Set<String> cardIds = data.stream()
                        .map(ProdTodayAmount::getCardId)
                        .collect(Collectors.toSet());
                
                if (cardIds.isEmpty()) {
                    return new HashMap<>();
                }
                
                List<ProdProdCardProcess> processes = prodProdCardProcessMapper.selectByCardIds(new ArrayList<>(cardIds));
                return processes.stream()
                        .collect(Collectors.toMap(ProdProdCardProcess::getCardId, ProdProdCardProcess::getStitchDensity));
            } catch (Exception e) {
                System.err.println("异步加载密度数据失败：" + e.getMessage());
                return new HashMap<>();
            }
        });
    }
    
    /**
     * 异步加载物料数据
     */
    private CompletableFuture<Map<String, String>> loadMaterialDataAsync(List<ProdTodayAmount> data) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                Set<String> cardIds = data.stream()
                        .map(ProdTodayAmount::getCardId)
                        .collect(Collectors.toSet());
                
                Map<String, String> materialMap = new ConcurrentHashMap<>();
                cardIds.parallelStream().forEach(cardId -> {
                    try {
                        String materialName = prodProdCardMapper.selectMaterialNameByCardId(cardId);
                        if (materialName != null && !materialName.trim().isEmpty()) {
                            materialMap.put(cardId, materialName);
                        } else {
                            materialMap.put(cardId, "坯布" + cardId);
                        }
                    } catch (Exception e) {
                        materialMap.put(cardId, "坯布" + cardId);
                    }
                });
                
                return materialMap;
            } catch (Exception e) {
                System.err.println("异步加载物料数据失败：" + e.getMessage());
                return new HashMap<>();
            }
        });
    }
    
    /**
     * 异步加载疵点数据
     */
    private CompletableFuture<Map<String, String>> loadFlawDataAsync(List<ProdTodayAmount> data) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                Set<String> prodIds = data.stream()
                        .map(ProdTodayAmount::getProdId)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toSet());
                
                Map<String, String> flawMap = new ConcurrentHashMap<>();
                prodIds.parallelStream().forEach(prodId -> {
                    try {
                        String flawTypes = FlawTypeUtil.getFlawTypesStringByProductId(prodId, prodFlawMapper);
                        flawMap.put(prodId, flawTypes);
                    } catch (Exception e) {
                        flawMap.put(prodId, "");
                    }
                });
                
                return flawMap;
            } catch (Exception e) {
                System.err.println("异步加载疵点数据失败：" + e.getMessage());
                return new HashMap<>();
            }
        });
    }
    
    /**
     * 异步加载车速数据（批量优化）
     */
    private CompletableFuture<Map<String, Integer>> loadSpeedDataAsync(List<ProdTodayAmount> data, LocalDate startDate, LocalDate endDate) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 按机台分组，减少重复查询
                Map<String, List<ProdTodayAmount>> machineGroups = data.stream()
                        .collect(Collectors.groupingBy(ProdTodayAmount::getMachineId));
                
                Map<String, Integer> speedMap = new ConcurrentHashMap<>();
                
                machineGroups.entrySet().parallelStream().forEach(entry -> {
                    String machineId = entry.getKey();
                    List<ProdTodayAmount> machineData = entry.getValue();
                    
                    try {
                        // 为每个机台计算一个平均车速（基于整个时间范围）
                        LocalDateTime startDateTime = startDate.atStartOfDay();
                        LocalDateTime endDateTime = endDate.atTime(23, 59, 59);
                        
                        Double avgSpeed = factoryMachineSpeedMapper.selectAverageSpeedByMachineIdAndTimeRange(
                                machineId, startDateTime, endDateTime);
                        
                        int speed = (avgSpeed != null) ? (int) Math.round(avgSpeed) : 0;
                        speedMap.put(machineId, speed);
                        
                    } catch (Exception e) {
                        speedMap.put(machineId, 0);
                    }
                });
                
                return speedMap;
            } catch (Exception e) {
                System.err.println("异步加载车速数据失败：" + e.getMessage());
                return new HashMap<>();
            }
        });
    }
    
    /**
     * 构建导出数据
     */
    private List<ProdTodayAmountExportDto> buildExportData(List<ProdTodayAmount> data,
                                                          Map<String, String> userMap,
                                                          Map<String, BigDecimal> densityMap,
                                                          Map<String, String> materialMap,
                                                          Map<String, String> flawMap,
                                                          Map<String, Integer> speedMap) {
        
        return data.parallelStream().map(item -> {
            try {
                ProdTodayAmountExportDto dto = new ProdTodayAmountExportDto();
                
                // 设置基本信息
                dto.setDate(item.getCreateTime().toLocalDate());
                dto.setMachineId(item.getMachineId());
                dto.setProductName(materialMap.getOrDefault(item.getCardId(), "坯布" + item.getCardId()));
                dto.setSubClothSeq(item.getSubClothSeq());
                dto.setAmount(item.getAmount());
                dto.setQualityStatus(flawMap.getOrDefault(item.getProdId(), ""));
                dto.setWorkerName(userMap.getOrDefault(item.getUserId(), item.getUserId()));
                dto.setStartTime(item.getCreateTime());
                dto.setUpdateTime(item.getUpdateTime());
                dto.setDensity(densityMap.getOrDefault(item.getCardId(), new BigDecimal("0.00")));
                dto.setSpeed(speedMap.getOrDefault(item.getMachineId(), 0));
                
                return dto;
            } catch (Exception e) {
                System.err.println("构建导出数据失败：" + e.getMessage());
                return null;
            }
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }
    
    /**
     * 生成Excel报表（优化版）
     */
    public byte[] generateExcelReportOptimized(List<ProdTodayAmountExportDto> data) {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("生产今日产量报表");
            
            // 创建样式
            CellStyle headerStyle = createHeaderStyle(workbook);
            CellStyle dataStyle = createDataStyle(workbook);
            
            // 创建标题行
            createHeaderRow(sheet, headerStyle);
            
            // 创建数据行
            createDataRows(sheet, data, dataStyle);
            
            // 输出到字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            return outputStream.toByteArray();
            
        } catch (Exception e) {
            System.err.println("生成Excel报表失败：" + e.getMessage());
            e.printStackTrace();
            throw new RuntimeException("生成Excel报表失败", e);
        }
    }
    
    private CellStyle createHeaderStyle(Workbook workbook) {
        CellStyle headerStyle = workbook.createCellStyle();
        Font headerFont = workbook.createFont();
        headerFont.setBold(true);
        headerFont.setColor(IndexedColors.WHITE.getIndex());
        headerStyle.setFont(headerFont);
        headerStyle.setAlignment(HorizontalAlignment.CENTER);
        headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headerStyle.setBorderTop(BorderStyle.THIN);
        headerStyle.setBorderBottom(BorderStyle.THIN);
        headerStyle.setBorderLeft(BorderStyle.THIN);
        headerStyle.setBorderRight(BorderStyle.THIN);
        return headerStyle;
    }
    
    private CellStyle createDataStyle(Workbook workbook) {
        CellStyle dataStyle = workbook.createCellStyle();
        dataStyle.setAlignment(HorizontalAlignment.CENTER);
        dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        dataStyle.setBorderTop(BorderStyle.THIN);
        dataStyle.setBorderBottom(BorderStyle.THIN);
        dataStyle.setBorderLeft(BorderStyle.THIN);
        dataStyle.setBorderRight(BorderStyle.THIN);
        return dataStyle;
    }
    
    private void createHeaderRow(Sheet sheet, CellStyle headerStyle) {
        Row headerRow = sheet.createRow(0);
        String[] headers = {"日期", "机台号", "品名", "分幅数", "工人", "上班时间", "下班时间", "班次产量", "车速", "密度", "质量状态"};
        
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
            cell.setCellStyle(headerStyle);
            sheet.setColumnWidth(i, 15 * 256);
        }
    }
    
    private void createDataRows(Sheet sheet, List<ProdTodayAmountExportDto> data, CellStyle dataStyle) {
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        
        for (int i = 0; i < data.size(); i++) {
            ProdTodayAmountExportDto dto = data.get(i);
            Row row = sheet.createRow(i + 1);
            
            // 日期
            row.createCell(0).setCellValue(dto.getDate().format(dateFormatter));
            // 机台号
            row.createCell(1).setCellValue(dto.getMachineId());
            // 品名
            row.createCell(2).setCellValue(dto.getProductName());
            // 分幅数
            row.createCell(3).setCellValue(dto.getSubClothSeq());
            // 工人
            row.createCell(4).setCellValue(dto.getWorkerName());
            // 上班时间
            row.createCell(5).setCellValue(dto.getStartTime() != null ? dto.getStartTime().format(timeFormatter) : "");
            // 下班时间
            row.createCell(6).setCellValue(dto.getUpdateTime() != null ? dto.getUpdateTime().format(timeFormatter) : "");
            // 班次产量
            row.createCell(7).setCellValue(dto.getAmount());
            // 车速
            row.createCell(8).setCellValue(dto.getSpeed());
            // 密度
            row.createCell(9).setCellValue(dto.getDensity().doubleValue());
            // 质量状态
            row.createCell(10).setCellValue(dto.getQualityStatus());
            
            // 设置样式
            for (int j = 0; j < 11; j++) {
                row.getCell(j).setCellStyle(dataStyle);
            }
        }
    }
}
